package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.exception.CustomException;
import com.heima.feigns.ArticleFeign;
import com.heima.feigns.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wmUser.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {
    @Autowired
    private WemediaFeign wemediaFeign;//远程调用自媒体微服务
    @Autowired
    private ArticleFeign articleFeign;//远程调用app微服务
    @Autowired
    private GreenTextScan greenTextScan;//注入文字审查工具类
    @Autowired
    private GreenImageScan greenImageScan;//注入图片审查工具类
    @Autowired
    private AdSensitiveMapper adSensitiveMapper;
    @Autowired
    private AdChannelMapper adChannelMapper;
    @Value("${file.oss.web-site}")
    private String webSite;
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public void autoScanByMediaNewsId(Integer wmNewsId) {
        log.info("开始自动审核");
        //判断数据是否合法
        if (wmNewsId == null) {
            log.error("自动审核文章失败,autoScanByMediaNewsId 传入参数为null");
            CustomException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据传入的id查看数据库中手存在该数据
        ResponseResult<WmNews> wmNewsResponseResult = wemediaFeign.findNewById(wmNewsId);
        if (wmNewsResponseResult.getCode() != 0) {
            log.error("自动审核文章失败，远程调用findNewById失败");
            CustomException.cust(AppHttpCodeEnum.SERVER_ERROR);
        }
        if (wmNewsResponseResult.getData() == null) {
            log.error("自动审核文章失败,wm_news数据库中不存在id={}的数据", wmNewsId);
            CustomException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        WmNews wmNews = wmNewsResponseResult.getData();
        Short status = wmNews.getStatus();
        long publishTime = wmNews.getPublishTime().getTime();
        if (status == null) {
            log.error("自动审核文章失败,当前文章审核状态异常，id===>{}", wmNewsId);
            CustomException.cust(AppHttpCodeEnum.LOGIN_STATUS_ERROR);
        }
        //判断当前文章的状态，如果是已经被人工审核则无需自动检测,直接发布文章
        if ((status == WmNews.Status.ADMIN_SUCCESS.getCode() || status == WmNews.Status.SUCCESS.getCode()) &&
                publishTime <= System.currentTimeMillis()) {
            publishArticle(wmNews);
            return;
        }
        //如果审核状态为待审核状态，则开始自动审核
        if (status == WmNews.Status.SUBMIT.getCode()) {
            //调用自动审核图片和自动审核内容的方法，开始自动审核
            boolean resImage = handleImages(wmNews);
            boolean resText = handleText(wmNews);
            //审核失败，修改文章状态，返回结果
            if (!resImage || !resText) return;
            updateWmNewsStatus(wmNews, WmNews.Status.SUCCESS.getCode(), "审核通过");
            //审核通过，判断有没有到达文章发的发布使时间
            if (publishTime <= System.currentTimeMillis()) {
                publishArticle(wmNews);
            }
        }

    }

    /**
     * 更新文章
     */
    private void updateWmNewsStatus(WmNews wmNews, Short status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        ResponseResult res = wemediaFeign.updateWmNews(wmNews);
        if (res.getCode() != 0) {
            log.error("wemediaFeign 远程调用 updateWmNews 出错 参数：{}  原因：{}", wmNews, res.getErrorMessage());
            CustomException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR, res.getErrorMessage());
        }
    }

    /**
     * 自动审核文字信息
     */
    private boolean handleText(WmNews wmNews) {
        //获取当前所有的文字信息
        List<Map> maps = JSONArray.parseArray(wmNews.getContent(), Map.class);
        String content = maps.stream()
                .filter(map -> Objects.equals(map.get("type"), "text"))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.joining("_"));
        content = wmNews.getTitle() + content;
        //判断文字信息非空
        if (StringUtils.isBlank(content)) {
            return true;
        }
        //初始化敏感词库
        List<String> allBySensitives = adSensitiveMapper.findAllBySensitives();
        SensitiveWordUtil.initMap(allBySensitives);
        //首先判断文章中是否有本地维护的敏感词
        Map<String, Integer> matchWords = SensitiveWordUtil.matchWords(content);
        if (matchWords.size() > 0) {
            //获取相关敏感词
            String reason = matchWords.keySet().stream()
                    .collect(Collectors.joining(","));
            reason = "包含以下敏感词" + reason;
            //审核未通过，调用更新文章信息
            updateWmNewsStatus(wmNews, WmNews.Status.FAIL.getCode(), reason);
            return false;
        }
        //调用阿里云的工具类判断
        try {
            Map map = greenTextScan.greenTextScan(content);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "block":
                    //添加敏感词
                    updateWmNewsStatus(wmNews, WmNews.Status.FAIL.getCode(), "包含敏感词");
                    return false;
                case "review":
                    //疑似敏感词，转为人工审核
                    updateWmNewsStatus(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "包含有疑似信息，转为人工审核");
                    return false;
            }
        } catch (Exception e) {
            log.error("阿里审核文字信息出错，文章内容：{}，报错原因：{}", content, e.getMessage());
            updateWmNewsStatus(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "阿里云审核出现异常转为人工审核");
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 自动审核图片
     */
    private boolean handleImages(WmNews wmNews) {
        //获取当前文章中的所有图片
        List<Map> maps = JSONArray.parseArray(wmNews.getContent(), Map.class);
        List<String> imageList = maps.stream()
                .filter(map -> Objects.equals(map.get("type"), "image"))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.toList());

        String coverImages = wmNews.getImages();
        if (StringUtils.isNotBlank(coverImages)) {
            String[] split = coverImages.split(",");
            List<String> listCover = Arrays.asList(split);
            List<String> collect = listCover.stream()
                    .map(str -> webSite + str)
                    .collect(Collectors.toList());
            imageList.addAll(collect);
        }
        List<String> images = imageList.stream().distinct().collect(Collectors.toList());
        //判断待审核图片集合是否为空
        if (CollectionUtils.isEmpty(images)) {
            return true;
        }
        //调用阿里云工具类开始自动审核
        try {
            Map map = greenImageScan.imageUrlScan(images);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "block":
                    updateWmNewsStatus(wmNews, WmNews.Status.FAIL.getCode(), "含有违规图片");
                    return false;
                case "review":
                    updateWmNewsStatus(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "包含疑似违规图片，转人工审核");
                    return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云自动审核图片失败，错误原因：{}", e.getMessage());
            updateWmNewsStatus(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "阿里云自动审核失败，转人工审核");
            return false;
        }
        return true;
    }


    /**
     * 发布文章
     */
    private void publishArticle(WmNews wmNews) {
        //判断数据是否合法
        if (wmNews == null || wmNews.getContent() == null) {
            CustomException.cust(AppHttpCodeEnum.PARAM_INVALID, "文章的内容不能为空！！！");
        }
        //获取文章状态，判断文章状态是不是为待发布状态
        Short status = wmNews.getStatus();
        if (status != WmNews.Status.SUCCESS.getCode()) {
            CustomException.cust(AppHttpCodeEnum.LOGIN_STATUS_ERROR, "文章状态不是待发布状态，请确认后重试");
        }
        //封装信息
        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmNews, articleDto);
        articleDto.setId(wmNews.getArticleId());
        articleDto.setFlag((byte) 0); // 普通文章
        articleDto.setLayout(wmNews.getType());// 布局
        articleDto.setWmUserId(wmNews.getUserId());// 用于获取作者信息
        AdChannel adChannel = adChannelMapper.selectById(wmNews.getChannelId());
        articleDto.setChannelName(adChannel.getName());
        ResponseResult<WmUser> wmUserById = wemediaFeign.findWmUserById(wmNews.getUserId());
        if (wmUserById.getCode() != 0) {
            log.error("wemediaFeign 远程调用 findWmUserById出错，原因：{}，参数：{}", wmUserById.getErrorMessage(), wmUserById);
            CustomException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR);
        }
        articleDto.setAuthorName(wmUserById.getData().getName());
        //使用ArticleFeign远程调用article微服务，执行添加方法
        ResponseResult res = articleFeign.addArticle(articleDto);
        //判断是否添加成功
        if (res.getCode() != 0) {
            log.error("ArticleFeign远程调用 addArticle方法异常，异常原因：{},参数为：{}", res.getErrorMessage(), wmNews);
            CustomException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR);
        }
        Long articleId = (Long) res.getData();
        wmNews.setArticleId(articleId);
        //修改自媒体端的文章状态
        updateWmNewsStatus(wmNews, WmNews.Status.PUBLISHED.getCode(), "已发布");
    }
}
